package com.thientan.timer

import grails.util.Holders

import java.text.SimpleDateFormat
import java.util.TimerTask

import org.apache.commons.io.FileUtils
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

import com.thientan.utils.Constants

class ThienTanBackupTask extends TimerTask {
	private static final Log LOGGER = LogFactory.getLog(ThienTanBackupTask.class)
	public static final String CONF_MYSQL_PATH = "MySQLPath"
	public static final String CONF_BACKUP_PATH = "BackupFolder"
	public static final String CONF_DB_NAME = "DBName"
	public static final String CONF_DB_PORT = "DBPort"
	public static final String CONF_DB_USER = "DBUser"
	public static final String CONF_DB_PASS = "DBPassword"

	@Override
	public void run() {
		try {
			Map configMap = readConfig()
			backupDatabase(configMap)
			storeExportedFilesAndCleanUp(configMap)
		} catch (Exception e) {
			LOGGER.error("Error occurred when executing database backup operation: ", e)
		}
	}

	private void backupDatabase(Map configMap) {
		// Create file and folder to store exported file.
		String timeInstance = new SimpleDateFormat(Constants.DATETIME_EXPORT).format(Calendar.instance.time)
		String backupFileName = "dbBackup_${timeInstance}.sql"
		String fullBackupPath = "${configMap.backupFolder}${File.separator}${backupFileName}"

		File backupFile = new File(fullBackupPath)
		if (backupFile.getParent() != null && !backupFile.getParentFile().exists()) {
			// Create folder if it doesn't exist
			backupFile.getParentFile().mkdirs()
		}

		// Specify database arguments to execute mysqldump.
		String mysqlPath = configMap["mysqlPath"]
		String dbName = configMap["dbName"]
		String dbUser = configMap["dbUser"]
		String dbPass = configMap["dbPassword"]
		String executeCmd = "${mysqlPath}${File.separator}mysqldump -u ${dbUser} -p${dbPass} --default-character-set=utf8 ${dbName} -r ${backupFile}"
		Process runtimeProcess =Runtime.getRuntime().exec(executeCmd)

		int processComplete = runtimeProcess.waitFor()
		if(processComplete == 0){
			LOGGER.info("Backup database successful!")
		} else {
			LOGGER.error("Unable to backup database!")
		}
	}

	private Map readConfig() {
		FileInputStream fis = null
		BufferedReader br = null
		Map dbConfigInfo = [:]
		try {
			String resourcePath = "${Holders.servletContext.getRealPath("")}${File.separator}conf${File.separator}application.conf"
			fis = new FileInputStream(resourcePath)
			br = new BufferedReader(new InputStreamReader(new DataInputStream(fis)))
			String strLine

			//Read File Line By Line
			while ((strLine = br.readLine()) != null)   {
				if(strLine.contains(CONF_MYSQL_PATH)) {
					putInfoToMap(strLine, dbConfigInfo, "mysqlPath")
				} else if (strLine.contains(CONF_BACKUP_PATH)) {
					putInfoToMap(strLine, dbConfigInfo, "backupFolder")
				} else if (strLine.contains(CONF_DB_NAME)) {
					putInfoToMap(strLine, dbConfigInfo, "dbName")
				} else if (strLine.contains(CONF_DB_PORT)) {
					putInfoToMap(strLine, dbConfigInfo, "dbPort")
				} else if (strLine.contains(CONF_DB_USER)) {
					putInfoToMap(strLine, dbConfigInfo, "dbUser")
				} else if (strLine.contains(CONF_DB_PASS)) {
					putInfoToMap(strLine, dbConfigInfo, "dbPassword")
				}
			}
		} catch (Exception e) {
			LOGGER.info("Error when reading configuration file", e)
		} finally {
			try {
				fis.close()
				br.close()
			} catch (Exception ex) {
				LOGGER.info("Error when closing configuration file", ex)
			}
		}
		dbConfigInfo
	}

	private void putInfoToMap(String strLine, Map dbConfigInfo, String key) {
		strLine = strLine.trim()
		String value = strLine.substring(strLine.lastIndexOf("=") + 1, strLine.length())
		dbConfigInfo.put(key, value)
	}

	private void storeExportedFilesAndCleanUp(Map configMap) {
		try {
			String exportPath = "${Holders.servletContext.getRealPath("")}${File.separator}exported"
			String importPath = "${Holders.servletContext.getRealPath("")}${File.separator}import"
			String backupPath = configMap["backupFolder"]
			File backupFolder = new File(backupPath)
			File exportFolder = new File(exportPath)
			if (exportFolder.exists()) {
				for (File file : exportFolder.listFiles()) {
					FileUtils.moveFileToDirectory(file, backupFolder, false)
					file.delete()
				}
			}

			File importFolder = new File(importPath)
			if (importFolder.exists()) {
				for (File file : importFolder.listFiles()) {
					FileUtils.moveFileToDirectory(file, backupFolder, false)
					file.delete()
				}
			}
		} catch (Exception e) {
			LOGGER.error("Error occurred when cleaning up server", e)
		}
	}
}
